
Skt.Canvas = L.Class.extend({

	includes: L.Mixin.Events,

	events: ['change'],
	
	options: {
		width: 100,
		height: 100,
		scale: 1
	},

	initialize: function(room, options) {
		L.Util.setOptions(this, options);

		this._room = room;
		this._elements = {};
		this._jMiniview = this._buildMiniview();
		this._miniview = this._jMiniview[0];
		
		// The Raphael context to draw on.
		this._raphael = Raphael(
			this._miniview, 
			this.options.width, 
			this.options.height
		);
		this._$svgNode = $(this._raphael.canvas);
		
		this._panzoom = this._raphael.panzoom({ 
			initialZoom: 0, 
			zoomStep: 0.1, 
			maxZoom: 9, 
			initialPosition: { 
				x: this.options.width/2,
				y: this.options.height/2
		}});
		
		this._panzoom.enable();
		this._scale = this.options.scale;
		
		this._room.on('objectAction', this._handleObjectAction, this);
		this._room.eachObject(this.onAddObject, this);
	},
	
	_buildMiniview: function() {
		var miniviewHtml = '<li id="room-' + this._room.getId()
		+ '" data-type="' + this._room.getType() 
		+ '" data-id="' + this._room.getId() 
		+ '" class="room"' 
		+ ' onclick="Skt.Slide.handleMiniviewClick(' + this._room.getId() 
		+ ');"></li>';
		
		return $(miniviewHtml);
	},

	// Sketch scaling
	scale: function(value, center) {
		//center default true
		center = (typeof center === "undefined" || center === null) ? true : center;

		var width = this.options.width;
		var height = this.options.height;

		// set new width and height to paper
		var svgNode = this._$svgNode[0];
		svgNode.setAttribute('width', width*value);
		svgNode.setAttribute('height', height*value);
		svgNode.setAttribute('viewBox', [0, 0, width, height].join(' '));

		var left=0, top=0, dx=0, dy=0;
		var cx = width/2 * (1-value);
		var cy = height/2 * (1-value);
		if (center) {
			left = cx;
			top = cy;
		}

		if ( typeof center == "object" ) {
			x = (center.x + parseInt(svgNode.style.left)) / this._scale;
			y = (center.y + parseInt(svgNode.style.top)) / this._scale;

			left = x * (1-value);
			top = y * (1-value);
		}

		svgNode.style.left = left;
		svgNode.style.top = top;

		// scale stroke width
		this._scale = value;
		this.redrawElements();
		Skt.Slide.updateEditorBackground();
	},

	zoomIn: function(center){
		this._panzoom.currPos = center || {
			x: this.options.width/2,
			y: this.options.height/2
		};
		this._panzoom.zoomIn(1);
		Skt.Slide.updateEditorBackground();
	},

	zoomOut: function(center){
		this._panzoom.currPos = center || {
			x: this.options.width/2,
			y: this.options.height/2
		};
		this._panzoom.zoomOut(-1);
		Skt.Slide.updateEditorBackground();
	},

	redrawElements: function() {
		var self = this;
		var elements = this._elements;

		this._raphael.forEach(function (raphaelEl) {
			var id = raphaelEl.data('elementId');
			if ( elements.hasOwnProperty(id) ) {
				var el = elements[id];
				el.onUpdate(self);
			} else {
				raphaelEl.remove();
			}
		});
	},

	//metodos publicos de actualizacion de elementos
	addElement: function(element) {
		if ( this._elements.hasOwnProperty(element.id) ) {
			console.log('[WARNING] L.Canvas.addElement reemplazo un elemento, id:'+ element.id);
		}
		this._room.addCommand('addObject',{object:element.serialize()});
	},

	removeElement: function(elementId) {
		if (!this._elements.hasOwnProperty(elementId)) {
			console.log('[WARNING] Skt.Canvas.removeElement intento eliminar un elemento inexistente');
		}
		this._room.addCommand('removeObject',{objectId:elementId});
	},

	updateElement: function(elementId, data){
		if(!this._elements.hasOwnProperty(elementId)){
			console.log('[WARNING] Skt.Canvas.sendCommand.updateElement intento actualizar elemento inexistente');
		}
		this._room.addCommand('updateObject', {objectId:elementId, data:data});
	},

	clearElements: function(){
		this._room.addCommand('changeStore', {store:{}});
	},

	_handleObjectAction: function(params /*action_name,attr_list*/) {
		switch(params.action_name) {
		case "addObject":
			this._onAddObject(params.attr_list);
			break;
		case "removeObject":
			this._onRemoveObject(params.attr_list);
			break;
		case "updateObject":
			this._onUpdateObject(params.attr_list);
			break;
		case "reloadObjects":
			this._onReloadObjects(params.attr_list);
			break;
		case "setBackground":
			this._onSetBackground(params.attr_list);
			break;
		}
		this.fire('change', {
			canvas: this
		});
	},

	onAddObject: function(object) {
		var element = Skt.ElementFactory.getElement(object);
		this._elements[object.id] = element;
		element.onAdd(this);
	},

	_onAddObject: function(attr_list) {
		var object = attr_list.object;
		var element = Skt.ElementFactory.getElement(object);
		this._elements[object.id] = element;
		element.onAdd(this);
	},

	_onRemoveObject: function(attr_list){
		var objectId = attr_list.objectId;
		element = this._elements[objectId];
		if ( element != null ) {
			element.onRemove(this);
			delete this._elements[objectId];
		}
	},

	_onUpdateObject: function(attr_list){
		var object = attr_list.object;
		if ( object != null ) {
			element = this._elements[object.id];
			element.attr(object);
		}
	},

	_onReloadObjects: function(){
		this.eachElement(function(element){
			this._onRemoveObject({'objectId':element.id});
		}, this);
		this._room.eachObject(function(object){
			this._onAddObject({'object':object});
		}, this);
	},
	
	_onSetBackground: function(attr_list) {
//		var background = attr_list.background;
	},


	/* funciones relacionadas con el editor */
	onAdd: function (editor) {
		//guardar referencia al editor
		this._editor = editor;
		
		this.eachElement(function(element){
			element.bindEvents();
		});
		
		this.defineEvents();

		var svgNode = this._$svgNode[0];

		svgNode.addEventListener('mousedown', this._onMousedown, false);
		svgNode.addEventListener('mousemove', this._onMousemove, false);
		svgNode.addEventListener('mouseup', this._onMouseup, false);
		svgNode.addEventListener('touchstart', this._onTouchstart, false);
		svgNode.addEventListener('touchmove', this._onTouchmove, false);
		svgNode.addEventListener('touchend', this._onTouchend, false);

		// Handle the case when the mouse is released outside the canvas.
		document.addEventListener('mouseup', this._onMouseup, false);
		document.addEventListener('touchend', this._onTouchend, false);    
	},

	onRemove: function(editor) {
		//deattach events
		
		this.eachElement(function(element){
			element.unbindEvents();
		});

		var svgNode = this._$svgNode[0];

		svgNode.removeEventListener('mousedown', this._onMousedown, false);
		svgNode.removeEventListener('mousemove', this._onMousemove, false);
		svgNode.removeEventListener('mouseup', this._onMouseup, false);
		svgNode.removeEventListener('touchstart', this._onTouchstart, false);
		svgNode.removeEventListener('touchmove', this._onTouchmove, false);
		svgNode.removeEventListener('touchend', this._onTouchend, false);

		// Handle the case when the mouse is released outside the canvas.
		document.removeEventListener('mouseup', this._onMouseup, false);
		document.removeEventListener('touchend', this._onTouchend, false);    

		// eliminar referencia al editor
		this._editor = null;
	},

	defineEvents: function() {
		var self = this;

		//flag para evitar definer los listener mas de una vez
		if ( self._events_defined_ ) {
			return;
		} else {
			self._events_defined_ = true;
		}

		self._onMousedown = function _onMousedown(e){
			// Some feature detection to see which object to use
			e = e || window.event;
			self._editor.getTool().onDragstartCanvas(self, e);
		};

		self._onMousemove = function _onMousemove(e){
			// Some feature detection to see which object to use
			e = e || window.event;
			self._editor.getTool().onDragmoveCanvas(self, e);
		}; 

		self._onMouseup = function _onMouseup(e){
			// Some feature detection to see which object to use
			e = e || window.event;
			self._editor.getTool().onDragendCanvas(self, e);
		};

		self._onTouchstart = function _onTouchstart(e){
			e.preventDefault();

			if(e.touches.length == 1) {
				var touch = e.touches[0];
				self._onMousedown(touch);
			}
		};

		self._onTouchmove = function _onTouchmove(e){
			e.preventDefault();

			if (e.touches.length == 1) {
				var touch = e.touches[0];
				self._onMousemove(touch);
			}
		};

		self._onTouchend = function _onTouchend(e){
			self._onMouseup(e);
		};
	},

	editing: function() {
		return this._editor != null;
	},

	getPos: function(e) {
		if(!this._editor) return;
		var svgNode = this.getSVGNode()[0];

		var uupos = svgNode.createSVGPoint();
		uupos.x = e.pageX;
		uupos.y = e.pageY;

		var ctm = svgNode.getScreenCTM();
		if (ctm = ctm.inverse()){
			uupos = uupos.matrixTransform(ctm); 
			return {
				x: uupos.x,
				y: uupos.y
			};      
		}
	},

	eachElement: function (fn, context) {
		var elements = this._elements;
		for (var i in elements) {
			if (elements.hasOwnProperty(i))
				fn.call(context, elements[i]);
		}
		return this;
	},

	getElement: function(id) {
		if(this._elements.hasOwnProperty(id))
			return this._elements[id];
		
		console.log("[WARNING] Skt.Canvas.getElement retorna un elemento null");
		return null;
	},

	getSVGNode: function() {
		return this._$svgNode;
	},

	getRoom: function() {
		return this._room;
	},

	getRaphael: function() {
		return this._raphael;
	},
	
	getMiniview: function() {
		return this._miniview;
	},
	
	getJMiniview: function() {
		return this._jMiniview;
	},
	
	getPanzoom: function() {
		return this._panzoom;
	}

});